/**
 * @file ebex_filter_cfg.c
 *
 * @date Oct 18, 2011
 * @author seth
 *
 * @brief This file is part of EBEX State Estimator, created for the EBEX project
 *
 * This software is copyright (C) 2011 Columbia University
 *
 * EBEX State Estimator is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * EBEX State Estimator is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with EBEX State Estimator; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include <string.h>
#include <memory_util.h>
#include <log_util.h>
#include <random_util.h>

#include <gyros.h>
#include <starcamera.h>
#include <ebex_quaternion.h>
#include <ebex_genetic_select.h>
#include <ebex_genetic_mutate.h>
#include <data_file.h>
#include <ebex_statistics.h>

#include <ebex_cfg.h>
#include <ebex_filter_cfg.h>

ebex_filter_cfg_t filter_config = { 0 };

static int	ebex_filter_cfg_handle_section(const char *m_localvar __attribute__((unused)), const char *m_var __attribute__((unused)),
		const char *m_arguments __attribute__((unused)), const char *m_val __attribute__((unused)),
		ebex_cfg_flags_t m_flags __attribute__((unused)), void *m_extra __attribute__((unused)))
{
	return EBEX_SUCCESS;
}

static int	ebex_filter_cfg_handle_bootstrap_section(const char *m_localvar __attribute__((unused)), const char *m_var __attribute__((unused)),
		const char *m_arguments __attribute__((unused)), const char *m_val __attribute__((unused)),
		ebex_cfg_flags_t m_flags, void *m_extra )
{
	ebex_bootstrap_cfg_t *cfg = (ebex_bootstrap_cfg_t*) m_extra;

	/// Set the non-zero default values for the sample section
	if (m_flags == EBEX_CFG_FLAGS_SECTIONSTART)
	{
		cfg->max_iter = 2;
		cfg->repetitions = 1;
		cfg->num_sc_images = 2;
		cfg->err_tol = 25.0 / 3600.0;
		cfg->de_numvec = 1;
		cfg->population_size = 20;
		cfg->de_maxweight = 0.5;
		cfg->de_minweight = 0.5;
	}


	return EBEX_SUCCESS;
}

static int	ebex_filter_cfg_handle_sample_section(const char *m_localvar __attribute__((unused)), const char *m_var __attribute__((unused)),
		const char *m_arguments __attribute__((unused)), const char *m_val __attribute__((unused)),
		ebex_cfg_flags_t m_flags, void *m_extra )
{
	random_sample_t *sample = (random_sample_t*) m_extra;

	/// Set the non-zero default values for the sample section
	if (m_flags == EBEX_CFG_FLAGS_SECTIONSTART)
		sample->scale = 1.0;

	return EBEX_SUCCESS;
}

static int	ebex_filter_cfg_handle_sensor_section(const char *m_localvar, const char *m_var __attribute__((unused)),
		const char *m_arguments __attribute__((unused)), const char *m_val __attribute__((unused)),
		ebex_cfg_flags_t m_flags, void *m_extra __attribute__((unused)))
{
	if (m_flags == EBEX_CFG_FLAGS_SECTIONEND)
		return EBEX_SUCCESS;

	if (m_flags != EBEX_CFG_FLAGS_SECTIONSTART)
		return EBEX_FAIL;


	if (!strncasecmp(m_localvar, "gyro_box",8))
	{
		filter_config.num_gyros++;
	}
	if (!strncasecmp(m_localvar, "sc",2))
	{
		filter_config.num_sc++;
	}

	return EBEX_SUCCESS;
}

static int	ebex_filter_cfg_handle_sample_type(const char *m_localvar __attribute__((unused)), const char *m_var __attribute__((unused)),
		const char *m_arguments __attribute__((unused)), const char *m_val,
		ebex_cfg_flags_t m_flags __attribute__((unused)), void *m_extra)
{
	e_random_dist *samp_type = (e_random_dist*)m_extra;

	for (random_dist_lookup_t *temp = random_dist_lookup_table; temp->position < random_dist_tblEnd; temp++)
	{
		if (!strncasecmp(m_val, temp->text, strnlen(temp->text, 32)))
		{
			*samp_type = temp->position;
			break;
		}
	}

	return EBEX_SUCCESS;
}


static int	ebex_filter_cfg_handle_kernel_type(const char *m_localvar __attribute__((unused)), const char *m_var __attribute__((unused)),
		const char *m_arguments __attribute__((unused)), const char *m_val,
		ebex_cfg_flags_t m_flags __attribute__((unused)), void *m_extra)
{
	e_kernel_type *samp_type = (e_kernel_type*)m_extra;

	*samp_type = kernel_type_none;
	for (kernel_type_lookup_t *temp = kernel_type_lookup_table; temp->position < kernel_type_tblEnd; temp++)
	{
		if (!strncasecmp(m_val, temp->text, strnlen(temp->text, 32)))
		{
			*samp_type = temp->position;
			break;
		}
	}

	if (*samp_type == kernel_type_none) return EBEX_FAIL;
	return EBEX_SUCCESS;
}

static int	ebex_filter_cfg_handle_unit_type(const char *m_localvar __attribute__((unused)), const char *m_var __attribute__((unused)),
	const char *m_arguments __attribute__((unused)), const char *m_val,
	ebex_cfg_flags_t m_flags __attribute__((unused)), void *m_extra )
{
	data_unit_types_t *unit = (data_unit_types_t*)m_extra;

	*unit = (data_unit_types_t)-1;
	if (!strncasecmp(m_val, "degree", 3) ) *unit = DATA_UNIT_DEGREES;
	else if (!strncasecmp(m_val, "radian", 3) ) *unit = DATA_UNIT_RADIANS;
	else if (!strncasecmp(m_val, "second", 1) ) *unit = DATA_UNIT_SECONDS;
	else if (!strncasecmp(m_val, "millisecond", 3) || !strncmp(m_val, "ms", 3)) *unit = DATA_UNIT_MS;

	if (*unit == -1) return EBEX_FAIL;

	return EBEX_SUCCESS;
}

static int ebex_filter_cfg_handle_log_level(const char *m_localvar __attribute__((unused)), const char *m_var __attribute__((unused)),
		const char *m_arguments __attribute__((unused)), const char *m_val,
		ebex_cfg_flags_t m_flags __attribute__((unused)), void *m_extra __attribute__((unused)))
{
	int i;

	for (i = 0; i < (int) log_level_tblEnd; i++)
	{
		if (!strncasecmp(m_val, log_level_lookup_table[i].text, sizeof(log_level_lookup_table[i].text)))
		{
			log_set_level(log_level_lookup_table[i].position);
			break;
		}
	}

	if ( i == log_level_tblEnd ) return EBEX_FAIL;

	return EBEX_SUCCESS;
}

static int ebex_filter_cfg_handle_log_file(const char *m_localvar __attribute__((unused)), const char *m_var __attribute__((unused)),
		const char *m_arguments __attribute__((unused)), const char *m_val,
		ebex_cfg_flags_t m_flags __attribute__((unused)), void *m_extra __attribute__((unused)))
{
	log_set_file(m_val);
	return EBEX_SUCCESS;
}

static int ebex_filter_cfg_handle_rng(const char *m_localvar __attribute__((unused)), const char *m_var __attribute__((unused)),
		const char *m_arguments __attribute__((unused)), const char *m_val,
		ebex_cfg_flags_t m_flags __attribute__((unused)), void *m_extra __attribute__((unused)))
{
	bool success = false;

	if (!strncasecmp("MCG31", m_val, 5)) success = ran_set_generator(RANDOM_MCG31);
	else if (!strncasecmp("MCG59", m_val, 5)) success = ran_set_generator(RANDOM_MCG59);
	else if (!strncasecmp("MRG32K3A", m_val, 8)) success = ran_set_generator(RANDOM_MRG32K3A);
	else if (!strncasecmp("WH", m_val, 2)) success = ran_set_generator(RANDOM_WH);
	else if (!strncasecmp("MT19937", m_val, 7)) success = ran_set_generator(RANDOM_MT19937);
	else if (!strncasecmp("MT2203", m_val, 6)) success = ran_set_generator(RANDOM_MT2203);
	else if (!strncasecmp("SFMT19937", m_val, 9)) success = ran_set_generator(RANDOM_SFMT19937);
	else if (!strncasecmp("SOBOL", m_val, 5)) success = ran_set_generator(RANDOM_SOBOL);
	else if (!strncasecmp("NIEDERR", m_val, 5)) success = ran_set_generator(RANDOM_NIEDERR);
	else if (!strncasecmp("IABSTRACT", m_val, 5)) success = ran_set_generator(RANDOM_IABSTRACT);
	else if (!strncasecmp("DABSTRACT", m_val, 5)) success = ran_set_generator(RANDOM_DABSTRACT);
	else if (!strncasecmp("SABSTRACT", m_val, 5)) success = ran_set_generator(RANDOM_SABSTRACT);

	if ( !success )
	{
		elog(log_level_warning, "Invalid generator '%s', using default instead", m_val);
		return EBEX_FAIL;
	}

	return EBEX_SUCCESS;
}

static int ebex_filter_cfg_handle_de_strategy(const char *m_localvar __attribute__((unused)), const char *m_var __attribute__((unused)),
		const char *m_arguments __attribute__((unused)), const char *m_val,
		ebex_cfg_flags_t m_flags __attribute__((unused)), void *m_extra __attribute__((unused)))
{
	if (!strncasecmp(m_val, "best", 4) || !strncmp(m_val, "1", 1)) filter_config.bootstrap.de_strategy = DIFF_EVO_STRATEGY_BEST;
	else if (!strncasecmp(m_val, "rand_to_best", 12) || !strncasecmp(m_val, "random_to_best", 14)
			|| !strncmp(m_val, "3", 1)) filter_config.bootstrap.de_strategy = DIFF_EVO_STRATEGY_RANDOMTOBEST;
	else if (!strncasecmp(m_val, "rand", 4) || !strncmp(m_val, "2", 1)) filter_config.bootstrap.de_strategy = DIFF_EVO_STRATEGY_RANDOM;

	if (filter_config.bootstrap.de_strategy) return EBEX_SUCCESS;

	return EBEX_FAIL;
}

static int ebex_filter_cfg_handle_de_crossover(const char *m_localvar __attribute__((unused)), const char *m_var __attribute__((unused)),
		const char *m_arguments __attribute__((unused)), const char *m_val,
		ebex_cfg_flags_t m_flags __attribute__((unused)), void *m_extra __attribute__((unused)))
{
	if (!strncasecmp(m_val, "exp", 3) || !strncmp(m_val, "1", 1)) filter_config.bootstrap.de_crossover = DIFF_EVO_CROSSOVER_EXPONENTIAL;
	else if (!strncasecmp(m_val, "bin", 3) || !strncmp(m_val, "2", 1)) filter_config.bootstrap.de_crossover = DIFF_EVO_CROSSOVER_BINOMIAL;

	if (filter_config.bootstrap.de_crossover) return EBEX_SUCCESS;

	return EBEX_FAIL;
}

static int ebex_filter_cfg_handle_de_reference(const char *m_localvar __attribute__((unused)), const char *m_var __attribute__((unused)),
		const char *m_arguments __attribute__((unused)), const char *m_val,
		ebex_cfg_flags_t m_flags __attribute__((unused)), void *m_extra __attribute__((unused)))
{
	if (!strncasecmp(m_val, "mean", 3) || !strncmp(m_val, "1", 1)) filter_config.bootstrap.de_reference = DIFF_EVO_REFERENCE_MEAN;
	else if (!strncasecmp(m_val, "best", 3) || !strncmp(m_val, "2", 1)) filter_config.bootstrap.de_reference = DIFF_EVO_REFERENCE_BEST;
	else if (!strncasecmp(m_val, "rand", 3) || !strncmp(m_val, "3", 1)) filter_config.bootstrap.de_reference = DIFF_EVO_REFERENCE_RANDOM;

	if (filter_config.bootstrap.de_reference) return EBEX_SUCCESS;

	return EBEX_FAIL;
}

static int ebex_filter_cfg_handle_de_seeding(const char *m_localvar __attribute__((unused)), const char *m_var __attribute__((unused)),
		const char *m_arguments __attribute__((unused)), const char *m_val,
		ebex_cfg_flags_t m_flags __attribute__((unused)), void *m_extra __attribute__((unused)))
{
	if (!strncasecmp(m_val, "uniform", 3) || !strncmp(m_val, "1", 1)) filter_config.bootstrap.seed_strategy = GENETIC_SEED_UNIFORM;
	else if (!strncasecmp(m_val, "gaussian", 3) || !strncmp(m_val, "2", 1)) filter_config.bootstrap.seed_strategy = GENETIC_SEED_GAUSSIAN;
	else if (!strncasecmp(m_val, "sample", 3) || !strncmp(m_val, "3", 1)) filter_config.bootstrap.seed_strategy = GENETIC_SEED_SAMPLE;
	else if (!strncasecmp(m_val, "zero", 3) || !strncmp(m_val, "4", 1)) filter_config.bootstrap.seed_strategy = GENETIC_SEED_ZERO;

	if (filter_config.bootstrap.seed_strategy) return EBEX_SUCCESS;

	return EBEX_FAIL;
}

static int ebex_filter_cfg_handle_ga_elitism(const char *m_localvar __attribute__((unused)), const char *m_var __attribute__((unused)),
		const char *m_arguments __attribute__((unused)), const char *m_val,
		ebex_cfg_flags_t m_flags __attribute__((unused)), void *m_extra __attribute__((unused)))
{
	if (!strncasecmp(m_val, "parentssurvive", 3) || !strncmp(m_val, "1", 1))
		filter_config.steady_state.elitism_type = GENETIC_SELECTION_PARENTS_SURVIVE;
	else if (!strncasecmp(m_val, "oneparentdies", 13) || !strncasecmp(m_val, "oneparentsurvives", 14) || !strncmp(m_val, "2", 1))
		filter_config.steady_state.elitism_type = GENETIC_SELECTION_ONE_PARENT_SURVIVES;
	else if (!strncasecmp(m_val, "parentsdie", 10) || !strncmp(m_val, "3", 1))
		filter_config.steady_state.elitism_type = GENETIC_SELECTION_PARENTS_DIE;
	else if (!strncasecmp(m_val, "parentseval", 11) || !strncasecmp(m_val, "evalparents", 11) || !strncasecmp(m_val, "rescore", 7) || !strncmp(m_val, "4", 1))
		filter_config.steady_state.elitism_type = GENETIC_SELECTION_RESCORE_PARENTS;

	if (filter_config.bootstrap.seed_strategy) return EBEX_SUCCESS;

	return EBEX_FAIL;
}

static int ebex_filter_cfg_handle_ga_evolution_type(const char *m_localvar __attribute__((unused)), const char *m_var __attribute__((unused)),
		const char *m_arguments __attribute__((unused)), const char *m_val,
		ebex_cfg_flags_t m_flags __attribute__((unused)), void *m_extra __attribute__((unused)))
{
	const char delim[] = " ,	";
	char *temp = strdupa(m_val);
	char *token;

	while ((token = strsep(&temp, delim)))
	{
		if (!strncasecmp(token, "lamarckparents", 8) || !strncmp(token, "1", 1))
			filter_config.steady_state.evolution_type &= EVOLUTION_MODE_LAMARCK_PARENTS;
		if (!strncasecmp(token, "lamarckchildren", 8) || !strncmp(token, "2", 1))
			filter_config.steady_state.evolution_type &= EVOLUTION_MODE_LAMARCK_CHILDREN;

		if (!strncasecmp(token, "baldwinparents", 8) || !strncmp(token, "3", 1))
			filter_config.steady_state.evolution_type &= EVOLUTION_MODE_BALDWIN_PARENTS;
		if (!strncasecmp(token, "baldwinchildren", 8) || !strncmp(token, "4", 1))
			filter_config.steady_state.evolution_type &= EVOLUTION_MODE_BALDWIN_CHILDREN;
	}

	return EBEX_SUCCESS;
}

static int ebex_filter_cfg_handle_ga_adaptation_type(const char *m_localvar __attribute__((unused)), const char *m_var __attribute__((unused)),
		const char *m_arguments __attribute__((unused)), const char *m_val,
		ebex_cfg_flags_t m_flags __attribute__((unused)), void *m_extra __attribute__((unused)))
{

	if (!strncasecmp(m_val, "random", 3) || !strncmp(m_val, "1", 1))
		filter_config.steady_state.adaptation_type = HILL_CLIMB_MODE_RANDOM;
	if (!strncasecmp(m_val, "systematic", 3) || !strncmp(m_val, "2", 1))
		filter_config.steady_state.adaptation_type = HILL_CLIMB_MODE_SYSTEMATIC;

	return EBEX_SUCCESS;
}

static int ebex_filter_cfg_handle_ga_selection_type(const char *m_localvar __attribute__((unused)), const char *m_var __attribute__((unused)),
		const char *m_arguments __attribute__((unused)), const char *m_val,
		ebex_cfg_flags_t m_flags __attribute__((unused)), void *m_extra)
{
	int i;
	e_genetic_select_type *result = (e_genetic_select_type*)m_extra;

	for (i = 0; genetic_select_type_lookup_table[i].position < genetic_select_type_tblEnd; i++)
	{
		if (!strncasecmp(genetic_select_type_lookup_table[i].text, m_val, strlen(genetic_select_type_lookup_table[i].text)))
		{
			*result = (e_genetic_select_type)genetic_select_type_lookup_table[i].position;
			break;
		}
	}

	if (genetic_select_type_lookup_table[i].position >= genetic_select_type_tblEnd) return EBEX_FAIL;

	return EBEX_SUCCESS;
}

static int ebex_filter_cfg_handle_ga_mutation_type(const char *m_localvar __attribute__((unused)), const char *m_var __attribute__((unused)),
		const char *m_arguments __attribute__((unused)), const char *m_val,
		ebex_cfg_flags_t m_flags __attribute__((unused)), void *m_extra)
{
	int i;
	e_genetic_mutation_type *result = (e_genetic_mutation_type*)m_extra;

	for (i = 0; genetic_mutation_type_lookup_table[i].position < genetic_mutation_type_tblEnd; i++)
	{
		if (!strncasecmp(genetic_mutation_type_lookup_table[i].text, m_val, strlen(genetic_mutation_type_lookup_table[i].text)))
		{
			*result = (e_genetic_mutation_type) genetic_mutation_type_lookup_table[i].position;
			break;
		}
	}

	if (genetic_mutation_type_lookup_table[i].position >= genetic_mutation_type_tblEnd) return EBEX_FAIL;

	return EBEX_SUCCESS;
}

static int ebex_filter_cfg_handle_ga_mating_type(const char *m_localvar __attribute__((unused)), const char *m_var __attribute__((unused)),
		const char *m_arguments __attribute__((unused)), const char *m_val,
		ebex_cfg_flags_t m_flags __attribute__((unused)), void *m_extra)
{
	int i;
	e_genetic_mating_type *result = (e_genetic_mating_type*)m_extra;

	for (i = 0; genetic_mating_type_lookup_table[i].position < genetic_mating_type_tblEnd; i++)
	{
		if (!strncasecmp(genetic_mating_type_lookup_table[i].text, m_val, strlen(genetic_mating_type_lookup_table[i].text)))
		{
			*result = (e_genetic_mating_type)genetic_mating_type_lookup_table[i].position;
			break;
		}
	}

	if (genetic_mating_type_lookup_table[i].position >= genetic_mutation_type_tblEnd) return EBEX_FAIL;

	return EBEX_SUCCESS;
}

static int ebex_filter_cfg_handle_pf_quat_filter_type(const char *m_localvar __attribute__((unused)), const char *m_var __attribute__((unused)),
		const char *m_arguments __attribute__((unused)), const char *m_val,
		ebex_cfg_flags_t m_flags __attribute__((unused)), void *m_extra)
{
	int i;
	e_ebex_quat_filter_type *result = (e_ebex_quat_filter_type*)m_extra;

	for (i = 0; ebex_quat_filter_type_lookup_table[i].position < ebex_quat_filter_type_tblEnd; i++)
	{
		if (!strncasecmp(ebex_quat_filter_type_lookup_table[i].text, m_val, strlen(ebex_quat_filter_type_lookup_table[i].text)))
		{
			*result = (e_ebex_quat_filter_type)ebex_quat_filter_type_lookup_table[i].position;
			break;
		}
	}

	if (ebex_quat_filter_type_lookup_table[i].position >= ebex_quat_filter_type_tblEnd) return EBEX_FAIL;

	return EBEX_SUCCESS;
}

static int ebex_filter_cfg_handle_file_type(const char *m_localvar __attribute__((unused)), const char *m_var __attribute__((unused)),
		const char *m_arguments __attribute__((unused)), const char *m_val,
		ebex_cfg_flags_t m_flags __attribute__((unused)), void *m_extra)
{
	data_file_t *result = (data_file_t*)m_extra;

	result->type = DATA_FILE_NONE;

	if (!strncasecmp(m_val, "raw", 3))
		result->type = DATA_FILE_RAW;
	if (!strncasecmp(m_val, "ascii", 5) || !strncmp(m_val, "text", 4))
		result->type = DATA_FILE_ASCII;
	if (!strncasecmp(m_val, "dirfile", 5))
			result->type = DATA_FILE_DIRFILE;
	if (!strncasecmp(m_val, "netcdf", 5))
			result->type = DATA_FILE_NETCDF;

	if (result->type == DATA_FILE_NONE) return EBEX_FAIL;

	return EBEX_SUCCESS;
}

static inline void ebex_filter_sample_register(const char *m_prefix, random_sample_t *m_sample)
{
	char temp_str[128] = {0};

	ebex_cfg_register_handler(m_prefix, 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_sample_section, m_sample);

	snprintf(temp_str, 127, "%s.dist_type", m_prefix);
	ebex_cfg_register_handler(temp_str, '\0', ebex_cfg_var_type_none, ebex_filter_cfg_handle_sample_type, &m_sample->type);

	snprintf(temp_str, 127, "%s.alpha", m_prefix);
	ebex_cfg_register_var(temp_str, ebex_cfg_var_type_double, &m_sample->beta.a, 0);

	snprintf(temp_str, 127, "%s.beta", m_prefix);
	ebex_cfg_register_var(temp_str, ebex_cfg_var_type_double, &m_sample->beta.b, 0);

	snprintf(temp_str, 127, "%s.mean", m_prefix);
	ebex_cfg_register_var(temp_str, ebex_cfg_var_type_double, &m_sample->gaussian.mean, 0);

	snprintf(temp_str, 127, "%s.stddev", m_prefix);
	ebex_cfg_register_var(temp_str, ebex_cfg_var_type_double, &m_sample->gaussian.stddev, 0);

	snprintf(temp_str, 127, "%s.probability", m_prefix);
	ebex_cfg_register_var(temp_str, ebex_cfg_var_type_double, &m_sample->binomial.probability, 0);

	snprintf(temp_str, 127, "%s.trials", m_prefix);
	ebex_cfg_register_var(temp_str, ebex_cfg_var_type_double, &m_sample->binomial.trials, 0);

	snprintf(temp_str, 127, "%s.shape", m_prefix);
	ebex_cfg_register_var(temp_str, ebex_cfg_var_type_double, &m_sample->gamma.shape, 0);

	snprintf(temp_str, 127, "%s.scale", m_prefix);
	ebex_cfg_register_var(temp_str, ebex_cfg_var_type_double, &m_sample->gamma.scale, 0);

	snprintf(temp_str, 127, "%s.min", m_prefix);
	ebex_cfg_register_var(temp_str, ebex_cfg_var_type_double, &m_sample->uniform.min, 0);

	snprintf(temp_str, 127, "%s.max", m_prefix);
	ebex_cfg_register_var(temp_str, ebex_cfg_var_type_double, &m_sample->uniform.max, 0);

	snprintf(temp_str, 127, "%s.dist_scale", m_prefix);
	ebex_cfg_register_var(temp_str, ebex_cfg_var_type_double, &m_sample->scale, 0);

	snprintf(temp_str, 127, "%s.dist_offset", m_prefix);
	ebex_cfg_register_var(temp_str, ebex_cfg_var_type_double, &m_sample->offset, 0);

}

static void ebex_filter_cfg_register_gyro(void)
{
	char temp_str[128] = {0};

	char *params[] =
	{
		_gyro_params(,GYRO_STRING)
		0
	};
	size_t sample_offset[] =
	{
		_gyro_params(sample,GYRO_OFFSET)
		-1
	};
	size_t min_offset[] =
	{
		_gyro_params(min,GYRO_OFFSET)
		-1
	};
	size_t max_offset[] =
	{
		_gyro_params(max,GYRO_OFFSET)
		-1
	};
	size_t value_offset[] =
	{
		_gyro_params(value,GYRO_OFFSET)
		-1
	};
	size_t mutation_offset[] =
	{
		_gyro_params(mutation_likelihood,GYRO_OFFSET)
		-1
	};

	for (int box = 0; box < 2; box++)
	{
		snprintf(temp_str, 127, "sensors.gyro_box%d", box);
		ebex_cfg_register_handler(temp_str, 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_sensor_section, NULL);

		snprintf(temp_str, 127, "sensors.gyro_box%d.alignment", box);

		ebex_filter_sample_register(temp_str, &(filter_config.gyro_box[box].alignment_noise));
		snprintf(temp_str, 127, "sensors.gyro_box%d.alignment.mutation_likelihood", box);
		ebex_cfg_register_var(temp_str, ebex_cfg_var_type_double, &filter_config.gyro_box[box].mutation_likelihood, 0);

		snprintf(temp_str, 127, "sensors.gyro_box%d.alignment.roll", box);
		ebex_cfg_register_var(temp_str, ebex_cfg_var_type_double, &filter_config.gyro_box[box].rpy.x, 0);
		snprintf(temp_str, 127, "sensors.gyro_box%d.alignment.pitch", box);
		ebex_cfg_register_var(temp_str, ebex_cfg_var_type_double, &filter_config.gyro_box[box].rpy.y, 0);
		snprintf(temp_str, 127, "sensors.gyro_box%d.alignment.yaw", box);
		ebex_cfg_register_var(temp_str, ebex_cfg_var_type_double, &filter_config.gyro_box[box].rpy.z, 0);

		snprintf(temp_str, 127, "sensors.gyro_box%d.name", box);
		ebex_cfg_register_var(temp_str, ebex_cfg_var_type_string, &filter_config.gyro_box[box].name, 0);

		for (int gyro = 0; gyro < 3; gyro++)
		{
			int i = 0;

			snprintf(temp_str, 127, "sensors.gyro_box%d.gyro%d", box, gyro);
			ebex_cfg_register_handler(temp_str, 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_section, NULL);

			snprintf(temp_str, 127, "sensors.gyro_box%d.gyro%d.name", box, gyro);
			ebex_cfg_register_var(temp_str, ebex_cfg_var_type_string, &filter_config.gyro_box[box].gyro[gyro].name, 0);

			snprintf(temp_str, 127, "sensors.gyro_box%d.gyro%d.inverted", box, gyro);
			ebex_cfg_register_var(temp_str, ebex_cfg_var_type_boolean, &filter_config.gyro_box[box].gyro[gyro].is_inverted, 0);

			snprintf(temp_str, 127, "sensors.gyro_box%d.gyro%d.source", box, gyro);
			ebex_cfg_register_handler(temp_str, 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_section, NULL);

			snprintf(temp_str, 127, "sensors.gyro_box%d.gyro%d.source.filename", box, gyro);
			ebex_cfg_register_var(temp_str, ebex_cfg_var_type_string, &filter_config.gyro_files[box][gyro].filename, 0);

			snprintf(temp_str, 127, "sensors.gyro_box%d.gyro%d.source.type", box, gyro);
			ebex_cfg_register_handler(temp_str, '\0', ebex_cfg_var_type_none, ebex_filter_cfg_handle_file_type, &(filter_config.gyro_files[box][gyro]));
			snprintf(temp_str, 127, "sensors.gyro_box%d.gyro%d.source.offset", box, gyro);
			ebex_cfg_register_var(temp_str, ebex_cfg_var_type_sizet, &filter_config.gyro_files[box][gyro].offset, 0);
			snprintf(temp_str, 127, "sensors.gyro_box%d.gyro%d.source.delimiters", box, gyro);
			ebex_cfg_register_var(temp_str, ebex_cfg_var_type_string, &filter_config.gyro_files[box][gyro].conf.ascii.delimiters, 0);

			snprintf(temp_str, 127, "sensors.gyro_box%d.gyro%d.source.column", box, gyro);
			ebex_cfg_register_var(temp_str, ebex_cfg_var_type_sizet, &filter_config.gyro_files[box][gyro].conf.ascii.column, 0);
			snprintf(temp_str, 127, "sensors.gyro_box%d.gyro%d.source.stride", box, gyro);
			ebex_cfg_register_var(temp_str, ebex_cfg_var_type_sizet, &filter_config.gyro_files[box][gyro].stride, 0);

			snprintf(temp_str, 127, "sensors.gyro_box%d.gyro%d.source.units", box, gyro);
			ebex_cfg_register_handler(temp_str, 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_unit_type, &filter_config.gyro_files[box][gyro].units);

			while (params[i])
			{
				snprintf(temp_str, 127, "sensors.gyro_box%d.gyro%d.val_%s", box, gyro, params[i]);
				ebex_cfg_register_var(temp_str, ebex_cfg_var_type_double,
						((char*)&filter_config.gyro_box[box].gyro[gyro].param) + value_offset[i], 0);

				snprintf(temp_str, 127, "sensors.gyro_box%d.gyro%d.min_%s", box, gyro, params[i]);
				ebex_cfg_register_var(temp_str, ebex_cfg_var_type_double,
						((char*)&filter_config.gyro_box[box].gyro[gyro].param) + min_offset[i], 0);

				snprintf(temp_str, 127, "sensors.gyro_box%d.gyro%d.max_%s", box, gyro, params[i]);
				ebex_cfg_register_var(temp_str, ebex_cfg_var_type_double,
						((char*)&filter_config.gyro_box[box].gyro[gyro].param) + max_offset[i], 0);

				snprintf(temp_str, 127, "sensors.gyro_box%d.gyro%d.mutation_likelihood_%s", box, gyro, params[i]);
				ebex_cfg_register_var(temp_str, ebex_cfg_var_type_double,
						((char*)&filter_config.gyro_box[box].gyro[gyro].param) + mutation_offset[i], 0);

				snprintf(temp_str, 127, "sensors.gyro_box%d.gyro%d.%s", box, gyro, params[i]);
				ebex_filter_sample_register(temp_str, (random_sample_t*)(((char*)&filter_config.gyro_box[box].gyro[gyro].param) + sample_offset[i]));

				i++;
			}
		}

		snprintf(temp_str, 127, "sensors.gyro_box%d.time", box);
		ebex_cfg_register_handler(temp_str, 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_section, NULL);

		snprintf(temp_str, 127, "sensors.gyro_box%d.time.units", box);
		ebex_cfg_register_handler(temp_str, 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_unit_type, &filter_config.gyro_files[box][3].units);

		snprintf(temp_str, 127, "sensors.gyro_box%d.time.filename", box);
		ebex_cfg_register_var(temp_str, ebex_cfg_var_type_string, &filter_config.gyro_files[box][3].filename, 0);

		snprintf(temp_str, 127, "sensors.gyro_box%d.time.type", box);
		ebex_cfg_register_handler(temp_str, '\0', ebex_cfg_var_type_none, ebex_filter_cfg_handle_file_type, &(filter_config.gyro_files[box][3]));

		snprintf(temp_str, 127, "sensors.gyro_box%d.time.offset", box);
		ebex_cfg_register_var(temp_str, ebex_cfg_var_type_sizet, &filter_config.gyro_files[box][3].offset, 0);

		snprintf(temp_str, 127, "sensors.gyro_box%d.time.delimiters", box);
		ebex_cfg_register_var(temp_str, ebex_cfg_var_type_string, &filter_config.gyro_files[box][3].conf.ascii.delimiters, 0);

		snprintf(temp_str, 127, "sensors.gyro_box%d.time.column", box);
		ebex_cfg_register_var(temp_str, ebex_cfg_var_type_sizet, &filter_config.gyro_files[box][3].conf.ascii.column, 0);
		snprintf(temp_str, 127, "sensors.gyro_box%d.time.stride", box);
		ebex_cfg_register_var(temp_str, ebex_cfg_var_type_sizet, &filter_config.gyro_files[box][3].stride, 0);

	}
}

static void ebex_filter_cfg_register_sc(void)
{
	char *file[7] = {"roll", "el", "az", "time", "sigma_az", "sigma_el", "sigma_roll"};
	char temp_str[128] = {0};
	for (int box = 0; box < 2; box++)
	{
		snprintf(temp_str, 127, "sensors.sc%d", box);
		ebex_cfg_register_handler(temp_str, 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_sensor_section, NULL);
		snprintf(temp_str, 127, "sensors.sc%d.source", box);
		ebex_cfg_register_handler(temp_str, 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_sensor_section, NULL);

		/// Data Source configuration
		for (int j = 0; j < 7; j++)
		{
			snprintf(temp_str, 127, "sensors.sc%d.source.%s", box, file[j]);
			ebex_cfg_register_handler(temp_str, 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_section, NULL);
			snprintf(temp_str, 127, "sensors.sc%d.source.%s.filename", box, file[j]);
			ebex_cfg_register_var(temp_str, ebex_cfg_var_type_string, &filter_config.sc_files[box][j].filename, 0);
			snprintf(temp_str, 127, "sensors.sc%d.source.%s.type", box, file[j]);
			ebex_cfg_register_handler(temp_str, '\0', ebex_cfg_var_type_none, ebex_filter_cfg_handle_file_type, &(filter_config.sc_files[box][j]));
			snprintf(temp_str, 127, "sensors.sc%d.source.%s.delimiters", box, file[j]);
			ebex_cfg_register_var(temp_str, ebex_cfg_var_type_string, &filter_config.sc_files[box][j].conf.ascii.delimiters, 0);
			snprintf(temp_str, 127, "sensors.sc%d.source.%s.offset", box, file[j]);
			ebex_cfg_register_var(temp_str, ebex_cfg_var_type_sizet, &filter_config.sc_files[box][j].offset, 0);
			snprintf(temp_str, 127, "sensors.sc%d.source.%s.column", box, file[j]);
			ebex_cfg_register_var(temp_str, ebex_cfg_var_type_sizet, &filter_config.sc_files[box][j].conf.ascii.column, 0);
			snprintf(temp_str, 127, "sensors.sc%d.source.%s.stride", box, file[j]);
			ebex_cfg_register_var(temp_str, ebex_cfg_var_type_sizet, &filter_config.sc_files[box][j].stride, 0);


			snprintf(temp_str, 127, "sensors.sc%d.source.%s.units", box, file[j]);
			ebex_cfg_register_handler(temp_str, 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_unit_type, &filter_config.sc_files[box][j].units);
		}

		snprintf(temp_str, 127, "sensors.sc%d.time_lag", box);
		ebex_cfg_register_var(temp_str, ebex_cfg_var_type_double, &filter_config.sc[box].time_lag, 0);

		snprintf(temp_str, 127, "sensors.sc%d.alignment", box);
		ebex_filter_sample_register(temp_str, &(filter_config.sc[box].alignment_noise));
		snprintf(temp_str, 127, "sensors.sc%d.alignment.mutation_likelihood", box);
		ebex_cfg_register_var(temp_str, ebex_cfg_var_type_double, &filter_config.sc[box].mutation_likelihood, 0);

		snprintf(temp_str, 127, "sensors.sc%d.alignment.roll", box);
		ebex_cfg_register_var(temp_str, ebex_cfg_var_type_double, &filter_config.sc[box].rpy.x, 0);
		snprintf(temp_str, 127, "sensors.sc%d.alignment.pitch", box);
		ebex_cfg_register_var(temp_str, ebex_cfg_var_type_double, &filter_config.sc[box].rpy.y, 0);
		snprintf(temp_str, 127, "sensors.sc%d.alignment.yaw", box);
		ebex_cfg_register_var(temp_str, ebex_cfg_var_type_double, &filter_config.sc[box].rpy.z, 0);

		snprintf(temp_str, 127, "sensors.sc%d.measurement_variance", box);
		ebex_cfg_register_handler(temp_str, 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_sensor_section, NULL);
		snprintf(temp_str, 127, "sensors.sc%d.measurement_variance.roll", box);
		ebex_cfg_register_var(temp_str, ebex_cfg_var_type_double, &filter_config.sc[box].measurement_variance_rpy.x, 0);
		snprintf(temp_str, 127, "sensors.sc%d.measurement_variance.pitch", box);
		ebex_cfg_register_var(temp_str, ebex_cfg_var_type_double, &filter_config.sc[box].measurement_variance_rpy.y, 0);
		snprintf(temp_str, 127, "sensors.sc%d.measurement_variance.yaw", box);
		ebex_cfg_register_var(temp_str, ebex_cfg_var_type_double, &filter_config.sc[box].measurement_variance_rpy.z, 0);
	}
}

static void ebex_filter_cfg_register_parent_data(void)
{
	char *file[4] = {"roll", "el", "az"};
	char temp_str[128] = {0};

	snprintf(temp_str, 127, "parent");
	ebex_cfg_register_handler(temp_str, 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_sensor_section, NULL);

	/// Data Source configuration
	for (int j = 0; j < 3; j++)
	{
		snprintf(temp_str, 127, "parent.%s", file[j]);
		ebex_cfg_register_handler(temp_str, 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_section, NULL);

		snprintf(temp_str, 127, "parent.%s.filename", file[j]);
		ebex_cfg_register_var(temp_str, ebex_cfg_var_type_string, &filter_config.parent_files[j].filename, 0);
		snprintf(temp_str, 127, "parent.%s.type", file[j]);
		ebex_cfg_register_handler(temp_str, '\0', ebex_cfg_var_type_none, ebex_filter_cfg_handle_file_type, &(filter_config.parent_files[j]));
		snprintf(temp_str, 127, "parent.%s.delimiters", file[j]);
		ebex_cfg_register_var(temp_str, ebex_cfg_var_type_string, &filter_config.parent_files[j].conf.ascii.delimiters, 0);
		snprintf(temp_str, 127, "parent.%s.offset", file[j]);
		ebex_cfg_register_var(temp_str, ebex_cfg_var_type_sizet, &filter_config.parent_files[j].offset, 0);
		snprintf(temp_str, 127, "parent.%s.column", file[j]);
		ebex_cfg_register_var(temp_str, ebex_cfg_var_type_sizet, &filter_config.parent_files[j].conf.ascii.column, 0);
		snprintf(temp_str, 127, "parent.%s.stride", file[j]);
		ebex_cfg_register_var(temp_str, ebex_cfg_var_type_sizet, &filter_config.parent_files[j].stride, 0);

	}
}
static void ebex_filter_cfg_register_bootstrap(void)
{
	ebex_cfg_register_handler("bootstrap", 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_bootstrap_section, &filter_config.bootstrap);
	ebex_cfg_register_var("bootstrap.num_sc_images", ebex_cfg_var_type_int, &filter_config.bootstrap.num_sc_images, 0);
	ebex_cfg_register_var("bootstrap.sc_segment_jump", ebex_cfg_var_type_int, &filter_config.bootstrap.sc_segment_jump, 0);
	ebex_cfg_register_var("bootstrap.num_segments", ebex_cfg_var_type_int, &filter_config.bootstrap.num_segments, 0);
	ebex_cfg_register_var("bootstrap.error_tol", ebex_cfg_var_type_double, &filter_config.bootstrap.err_tol, 0);
	ebex_cfg_register_var("bootstrap.gyro_noise_limit", ebex_cfg_var_type_double, &filter_config.bootstrap.gyro_noise_limit, 0);
	ebex_cfg_register_var("bootstrap.var_tol", ebex_cfg_var_type_double, &filter_config.bootstrap.var_tol, 0);
	ebex_cfg_register_var("bootstrap.max_iter", ebex_cfg_var_type_sizet, &filter_config.bootstrap.max_iter, 0);
	ebex_cfg_register_var("bootstrap.force_exit", ebex_cfg_var_type_boolean, &filter_config.bootstrap.force_exit, 0);
	ebex_cfg_register_var("bootstrap.repetitions", ebex_cfg_var_type_sizet, &filter_config.bootstrap.repetitions, 0);
	ebex_cfg_register_var("bootstrap.num_vec", ebex_cfg_var_type_sizet, &filter_config.bootstrap.de_numvec, 0);
	ebex_cfg_register_var("bootstrap.crossover_ratio", ebex_cfg_var_type_double, &filter_config.bootstrap.de_crossover_ratio, 0);
	ebex_cfg_register_var("bootstrap.min_weight", ebex_cfg_var_type_double, &filter_config.bootstrap.de_minweight, 0);
	ebex_cfg_register_var("bootstrap.max_weight", ebex_cfg_var_type_double, &filter_config.bootstrap.de_maxweight, 0);
	ebex_cfg_register_var("bootstrap.population_size", ebex_cfg_var_type_sizet, &filter_config.bootstrap.population_size, 0);

	ebex_cfg_register_var("bootstrap.scatter", ebex_cfg_var_type_boolean, &filter_config.bootstrap.de_scatter, 0);
	ebex_cfg_register_var("bootstrap.scatter_min_improvement", ebex_cfg_var_type_double, &filter_config.bootstrap.de_scatter_min_improvement, 0);

	ebex_cfg_register_handler("bootstrap.strategy", 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_de_strategy, NULL);
	ebex_cfg_register_handler("bootstrap.crossover", 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_de_crossover, NULL);
	ebex_cfg_register_handler("bootstrap.seeding", 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_de_seeding, NULL);

	ebex_cfg_register_var("bootstrap.opposition_rate", ebex_cfg_var_type_double, &filter_config.bootstrap.de_opposition_rate, 0);
	ebex_cfg_register_handler("bootstrap.opposition_reference", 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_de_reference, NULL);

	ebex_cfg_register_handler("bootstrap.output", 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_section, NULL);
	ebex_cfg_register_var("bootstrap.output.filename", ebex_cfg_var_type_string, &filter_config.bootstrap.output_filename, 0);
	ebex_cfg_register_handler("bootstrap.output.type", '\0', ebex_cfg_var_type_none, ebex_filter_cfg_handle_file_type, &(filter_config.bootstrap.output_type));

	ebex_cfg_register_var("bootstrap.output.rotate", ebex_cfg_var_type_boolean, &filter_config.bootstrap.rotate_solution, 0);
	ebex_cfg_register_var("bootstrap.output.offset", ebex_cfg_var_type_boolean, &filter_config.bootstrap.offset_solution, 0);
	ebex_cfg_register_var("bootstrap.output.smooth", ebex_cfg_var_type_boolean, &filter_config.bootstrap.backward_smoothing, 0);
}

static void ebex_filter_cfg_register_ss(void)
{
	ebex_cfg_register_handler("steady_state", 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_section, NULL);
	ebex_cfg_register_var("steady_state.adapt_max_iter", ebex_cfg_var_type_sizet, &filter_config.steady_state.adaptation_max_iter, 0);
	ebex_cfg_register_var("steady_state.learning_ratio", ebex_cfg_var_type_double, &filter_config.steady_state.learning_ratio, 0);

	ebex_cfg_register_var("steady_state.generations_per_step", ebex_cfg_var_type_sizet, &filter_config.steady_state.generations_per_step, 0);
	ebex_cfg_register_var("steady_state.eval_segments", ebex_cfg_var_type_sizet, &filter_config.steady_state.eval_segments, 0);

	ebex_cfg_register_var("steady_state.population_parameter_size", ebex_cfg_var_type_sizet, &filter_config.steady_state.parameter_population_size, 0);
	ebex_cfg_register_var("steady_state.population_parameter_minimum_effective_size", ebex_cfg_var_type_sizet, &filter_config.steady_state.minimum_effective_size, 0);

	ebex_cfg_register_var("steady_state.population_state_size", ebex_cfg_var_type_sizet, &filter_config.steady_state.state_population_size, 0);
	ebex_cfg_register_var("steady_state.num_segments", ebex_cfg_var_type_sizet, &filter_config.steady_state.max_segments, 0);

	ebex_cfg_register_var("steady_state.mating_ratio", ebex_cfg_var_type_double, &filter_config.steady_state.mating_ratio, 0);
	ebex_cfg_register_var("steady_state.mutation_likelihood", ebex_cfg_var_type_double, &filter_config.steady_state.organism_mutation_likelihood, 0);
	ebex_cfg_register_handler("steady_state.mutation_selection_type", 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_ga_selection_type, &filter_config.steady_state.mutation_selection_type);
	ebex_cfg_register_handler("steady_state.mating_selection_type", 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_ga_selection_type, &filter_config.steady_state.mating_selection_type);

	ebex_cfg_register_handler("steady_state.evolution_type", 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_ga_evolution_type, NULL);
	ebex_cfg_register_handler("steady_state.adaptation_type", 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_ga_adaptation_type, NULL);
	ebex_cfg_register_handler("steady_state.elitism_type", 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_ga_elitism, NULL);

	ebex_cfg_register_handler("steady_state.mutation_type", 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_ga_mutation_type, &filter_config.steady_state.mutation_type);
	ebex_cfg_register_handler("steady_state.mating_type", 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_ga_mating_type, &filter_config.steady_state.mating_type);

	ebex_cfg_register_handler("steady_state.output", 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_section, NULL);
	ebex_cfg_register_var("steady_state.output.filename", ebex_cfg_var_type_string, &filter_config.steady_state.output_filename, 0);
	ebex_cfg_register_handler("steady_state.output.type", '\0', ebex_cfg_var_type_none, ebex_filter_cfg_handle_file_type, &(filter_config.steady_state.output_type));

	ebex_cfg_register_handler("steady_state.output.quaternion_estimator", 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_pf_quat_filter_type, &filter_config.steady_state.quaternion_filter_type);

	ebex_cfg_register_handler("steady_state.convergence", 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_section, NULL);
	ebex_cfg_register_var("steady_state.convergence.window_size", ebex_cfg_var_type_sizet, &filter_config.steady_state.convergence_window_size, 0);
	ebex_cfg_register_var("steady_state.convergence.sigma", ebex_cfg_var_type_double, &filter_config.steady_state.convergence_sigma, 0);
	ebex_cfg_register_var("steady_state.convergence.force_continue", ebex_cfg_var_type_boolean, &filter_config.steady_state.convergence_continue, 0);
}

static void ebex_filter_cfg_register_pf(void)
{
	ebex_cfg_register_handler("particle_filter", 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_section, NULL);

	ebex_cfg_register_var("particle_filter.initial_size", ebex_cfg_var_type_int, &filter_config.pf_configuration.initial_size, 0);
	ebex_cfg_register_var("particle_filter.min_effective_size", ebex_cfg_var_type_int, &filter_config.pf_configuration.minimum_effective_size, 0);

	ebex_cfg_register_handler("particle_filter.quaternion_estimator", 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_pf_quat_filter_type, &filter_config.pf_configuration.quaternion_filter_type);
	ebex_cfg_register_handler("particle_filter.quaternion_sample_type", '\0', ebex_cfg_var_type_none, ebex_filter_cfg_handle_sample_type,
			&(filter_config.pf_configuration.quaternion_sample.type));
	ebex_cfg_register_var("particle_filter.bandwidth", ebex_cfg_var_type_double, &filter_config.pf_configuration.bandwidth, 0);

}

static void ebex_filter_cfg_register_global(void)
{
	ebex_cfg_register_handler("log_level", 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_log_level, NULL);
	ebex_cfg_register_handler("log_file", 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_log_file, NULL);
	ebex_cfg_register_handler("random_generator", 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_rng, NULL);
	ebex_cfg_register_var("slerp_tolerance", ebex_cfg_var_type_double, &ebex_slerp_tol, 0);
	ebex_cfg_register_var("weighting_range", ebex_cfg_var_type_double, &filter_config.steady_state.weighting_range, 0);
	ebex_cfg_register_var("output_parent", ebex_cfg_var_type_boolean, &filter_config.output_parent, 0);
}

static void ebex_filter_cfg_register_sensors(void)
{
	ebex_cfg_register_handler("sensors", 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_section, NULL);
	ebex_cfg_register_var("sensors.reference_gyrobox", ebex_cfg_var_type_int, &filter_config.reference_gyrobox,0);
	ebex_cfg_register_var("sensors.gyro_rate", ebex_cfg_var_type_double, &filter_config.gyro_rate,0);

	ebex_cfg_register_var("sensors.smooth_gyros", ebex_cfg_var_type_boolean, &filter_config.smooth_gyros,0);
	ebex_cfg_register_var("sensors.smoothing_bandwidth", ebex_cfg_var_type_double, &filter_config.smoothing_bandwidth,0);
	ebex_cfg_register_handler("sensors.smoothing_kernel", 0, ebex_cfg_var_type_none, ebex_filter_cfg_handle_kernel_type, &filter_config.smoothing_kernel);
}

void ebex_filter_cfg_register(void)
{
	filter_config.bootstrap.num_segments = 1;


	ebex_filter_cfg_register_global();
	ebex_filter_cfg_register_parent_data();
	ebex_filter_cfg_register_sensors();
	ebex_filter_cfg_register_gyro();
	ebex_filter_cfg_register_sc();
	ebex_filter_cfg_register_bootstrap();
	ebex_filter_cfg_register_ss();

	ebex_filter_cfg_register_pf();


}
